﻿\subsection{获取物理内存信息}

操作系统需要提前获知计算机中可用的内存容量，否则操作系统内存管理无法进行。
实模式下的 \MiB{1} 内存布局有严格规定约定，这 \MiB{1} 中的可用空间可以全部分配给操作系统内核。
超过这 \MiB{1} 的内存空间信息只能通过调用 BIOS 中断获取。
BIOS 工作于 16 位实模式下，引导加载器的职责之一就是将处理器从 16 位实模式带入 32 位保护模式。
一旦进入 32 位保护模式，BIOS 中断就不再可用。
因此，获取物理内存信息是引导加载器开始执行后的第一项任务。

BIOS \lstinline{0x15} 号中断 \lstinline{0xE820} 号子功能（子功能号保存在 \lstinline{EAX} 寄存器中）可用于查询内存布局（表 \ref{BIOS_0xE820}）\cite{apic-doc}。
该子功能会向指定的内存区域写入一个称作地址范围描述符结构体（Address Range Descriptor Strcture，ARDS）的数据结构，并通过寄存器 \lstinline{EBX} 返回下一个 ARDS 的编号。
每个 ARDS 占用 \Bytes{20}，描述了一块具有某种特定属性的内存块。
通过返回的编号可反复调用该子功能迭代查询内存布局情况。
若干 ARDS 结构体连续存放，形成一张内存地址图（Memory Address Map），操作系统内核可解析并使用此数据结构完成内存分配。

\begin{figure}[h!]
\captionsetup{type=table}
\caption{BIOS 中断——获取内存地址范围}
\label{BIOS_0xE820}
\begin{minipage}{14cm}
    \Centering
    \begin{tabular}{|>{\RaggedRight\arraybackslash\small}p{10cm}|}
        \hline
        \Centering\textbf{BIOS 中断——获取内存地址范围}\\
        \hline
        中断：\verb{0x15}\\
        功能号：\verb{0xE820}（存放于 \verb{EAX} 寄存器）\\
        功能：向显存写入带属性的字符 \\
        \textbf{输入}\\
        \quad{}\verb{EBX} = \verb{0}\\
        \quad{}\verb{ES:DI} = 缓冲区指针 \\
        \quad{}\verb{ECX} = 用于存放单个地址范围描述符的内存块大小（以字节为单位）\\
        \quad{}\verb{EDX} = \verb{0x5041'4D53}\\
        \hline
        \textbf{输出}\\
        \quad{}\verb{EFLAGS.CF} = \verb{0} 成功获取内存信息 \\
        \quad{}\verb{EFLAGS.CF} = \verb{1} 出错 \\
        \quad{}\verb{EAX} = \verb{0x5041'4D53}\\
        \quad{}\verb{ES:DI} = 指向地址范围描述符的指针 \\
        \quad{}\verb{ECX} = 地址范围描述符占用的空间大小 \\
        \quad{}\verb{EBX} = 用于获取下个地址描述符的索引 \\
        \hline
        注：\\
        （1）{}\verb{EBX} 中存放地址描述符的索引号（初始值应设置为 \verb{0}），每获取到一个地址描述符，BIOS 将在 {}\verb{EBX} 中存放下个地址描述符的索引号作为返回值。当所有的地址范围描述符获取完毕时，BIOS 将 \verb{EBX} 的值设置为 \verb{0} 表示结束。\\
        （2）\verb{0x5041'4D53} 为字符串 \verb{"SMAP"} 的 ASCII 编码（小端方式）。\\
    \hline
    \end{tabular}
\end{minipage}
\end{figure}
